Introduction

Leaflet is one of the most popular open-source JavaScript libraries for interactive maps. It’s used by websites ranging from The New York Times and The Washington Post to GitHub and Flickr, as well as GIS specialists like OpenStreetMap, Mapbox, and CartoDB.

This R package makes it easy to integrate and control Leaflet maps in R.

Features

  • Interactive panning/zooming
  • Compose maps using arbitrary combinations of:
    • Map tiles
    • Markers
    • Polygons
    • Lines
    • Popups
    • GeoJSON
  • Create maps right from the R console or RStudio
  • Embed maps in knitr/R Markdown documents and Shiny apps
  • Easily render spatial objects from the sp or sf packages, or data frames with latitude/longitude columns
  • Use map bounds and mouse events to drive Shiny logic
  • Display maps in non spherical mercator projections
  • Augment map features using chosen plugins from leaflet plugins repository

Load library

library(leaflet)
library(tidyverse)

Functionality

Similar to the packages in the tidyverse, the leaflet package makes use of the pipe operator (i.e., %>%) from the magrittr package to chain function calls together. This means we can pipe the result of one function into another without having to store the intermediate output in an object.

mtcars  %>% 
    mutate(car = rownames(.))  %>% 
    select(car, mpg)  %>% 
    filter(mpg >= 25)  
##              car  mpg
## 1       Fiat 128 32.4
## 2    Honda Civic 30.4
## 3 Toyota Corolla 33.9
## 4      Fiat X1-9 27.3
## 5  Porsche 914-2 26.0
## 6   Lotus Europa 30.4

Map and Tiles

To create a web map in R, you will chain together a series of function calls using the %>% operator. Our first function leaflet() will initialize the htmlwidget then we will add a map tile using the addTiles() function. This provides the default base map tiles from OpenStreetMap

leaflet() %>%
    addTiles() %>% setView(-3.166340,54.913142, zoom = 5)

We can also select alternative third party tiles using the addProviderTiles() function.

leaflet() %>%
  addProviderTiles(providers$CartoDB.Positron) %>% setView(-3.166340,54.913142, zoom = 5)

You can also use addWMSTiles() to add WMS (Web Map Service) tiles. The below map shows the UK AIR web map tile showing modelled background and roadside air quality concentration maps from Defra’s national Pollution Climate Model (PCM).

leaflet() %>% addProviderTiles(providers$CartoDB.Positron) %>% setView(-3.166340,54.913142, zoom = 5) %>%
  addWMSTiles(
    "https://uk-air.defra.gov.uk/view/services/PCM/NO2Roads/MapServer/WMSServer",
    layers = "18",
    options = WMSTileOptions(format = "image/png", transparent = TRUE),
    attribution = "UK-AIR - OGC® Web Map Service Interface Standard"
  )

Markers

Use markers to call out points on the map. Marker locations are expressed in latitude/longitude coordinates, and can either appear as icons or as circles.

For example, the below markers indicate locations of Automatic Urban and Rural Network (AURN) air quality monitoring stations.

head(AURNMeta)
##    SiteCode                       SiteName Latitude Longitude Parameter
## 3       ABD                       Aberdeen 57.15736 -2.094278       NO2
## 17     ABD7 Aberdeen Union Street Roadside 57.14455 -2.106472       NO2
## 23     ABD8       Aberdeen Wellington Road 57.13389 -2.094198       NO2
## 29     ARM6                Armagh Roadside 54.35373 -6.654558       NO2
## 39       AH                     Aston Hill 52.50385 -3.034178       NO2
## 84     BAAR          Ballymena Antrim Road 54.85149 -6.274961       NO2
##       ParameterName  StartDate EndDate                zone agglomeration
## 3  Nitrogen dioxide 1999-09-18 ongoing North East Scotland          <NA>
## 17 Nitrogen dioxide 2008-01-01 ongoing North East Scotland          <NA>
## 23 Nitrogen dioxide 2016-02-09 ongoing North East Scotland          <NA>
## 29 Nitrogen dioxide 2009-01-01 ongoing    Northern Ireland          <NA>
## 39 Nitrogen dioxide 2003-10-21 ongoing         North Wales          <NA>
## 84 Nitrogen dioxide 2017-04-01 ongoing    Northern Ireland          <NA>
##    local_authority
## 3    Aberdeen City
## 17   Aberdeen City
## 23   Aberdeen City
## 29          Armagh
## 39           Powys
## 84       Ballymena
leaflet(data = AURNMeta) %>% addTiles() %>%
  addMarkers(~Longitude, ~Latitude, popup = ~as.character(SiteCode), label = ~as.character(SiteName))

Chloropleths

A choropleth map is a type of thematic map in which areas are shaded or patterned in proportion to a statistical variable that represents an aggregate summary of a geographic characteristic within each area, such as population density.

We can create these maps by reading existing data sources for area boundaries such as that of Local Authority Boundaries in England. We can read these as a JSON file format using the rgdal pacakge and it’s readOGR function. This reads the JSON file into R as an ‘SpatialPolygonsDataFrame’ class. This contains both spatial data to plot this on a map, and the supporting data for each of those geographical areas.

englandLA <- rgdal::readOGR("england_topo.json")
## OGR data source with driver: GeoJSON 
## Source: "/home/anthony/R/Education/england_topo.json", layer: "lad"
## with 326 features
## It has 5 fields

Once we have this data we can then simply plot the boundary shapes by ensuring the data is called in the leaflet map by containing it within the leaflet(data) %>% initial function call. Then by simply calling the function addPolygons()

leaflet(englandLA) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% setView(-3.166340,54.913142, zoom = 5) %>% addPolygons()

Lets now add some colour to the shapes! I’ve added the latest Public Health England Coronavirus data (as of 30/03/20), which indicates confirmed cases in each Local Authority.

We can then colour these Local Authority shapes by creating a colour palette with the colorBin() function. This is one of a few colour functions, this one specifically takes the data and colours it based on preset or automatic bins; i.e. grouping the data into ranges such as 0-10, 11-20, 21-30 etc. It’s easy to pre-call the colorBin() function into a variable such as “pal”, which can then be called just as pal() with all the options preset (colour palette, domain, bins).

We can set the specific bins by creating a bins variable and creating a numeric list defining each breakpoint of the bin as below.

To then set the colour, we simply cal the fillColor function, and then call the pre-made pal() function pointing to the “Cases” data vector inside our dataset.

bins <- c(0, 10, 20, 50, 100, 200, 500, 1000, Inf)
pal <- colorBin("YlOrRd", domain = englandLA$Cases, bins = bins)

leaflet(englandLA) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% setView(-3.166340,54.913142, zoom = 5) %>% addPolygons(
  fillColor = ~pal(Cases),
  weight = 2,
  opacity = 1,
  color = "white",
  dashArray = "3",
  fillOpacity = 0.7)

Lets add some interactivity when you scroll over the Local Authority. Easy to do with the highlight = option;

leaflet(englandLA) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% setView(-3.166340,54.913142, zoom = 5) %>% addPolygons(
  fillColor = ~pal(Cases),
  weight = 2,
  opacity = 1,
  color = "white",
  dashArray = "3",
  fillOpacity = 0.7,
  highlight = highlightOptions(
    weight = 5,
    color = "#666",
    dashArray = "",
    fillOpacity = 0.7,
    bringToFront = TRUE))

Now we can add label information for each of the Local Authorities with the label = option. Lables can take HTML formatting, and it’s usually easier to create the label variable outside the map function to keep things neater as below;

labels <- sprintf(
  "<strong>%s</strong><br/>%g cases of COVID-19",
  englandLA$LAD13NM, englandLA$Cases
) %>% lapply(htmltools::HTML)

leaflet(englandLA) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% setView(-3.166340,54.913142, zoom = 5) %>% addPolygons(
  fillColor = ~pal(Cases),
  weight = 2,
  opacity = 1,
  color = "white",
  dashArray = "3",
  fillOpacity = 0.7,
  highlight = highlightOptions(
    weight = 5,
    color = "#666",
    dashArray = "",
    fillOpacity = 0.7,
    bringToFront = TRUE),
  label = labels,
  labelOptions = labelOptions(
    style = list("font-weight" = "normal", padding = "3px 8px"),
    textsize = "15px",
    direction = "auto")) %>% addLegend(pal = pal, values = ~density, opacity = 0.7, title = "COVID-19 cases (as of 30/03/20)",
  position = "bottomright")
## Warning in is.na(values): is.na() applied to non-(list or vector) of type
## 'closure'

http://rstudio.github.io/leaflet/

https://cran.r-project.org/web/packages/leaflet/leaflet.pdf

https://data.gov.uk/dataset/daaafdcc-f7c7-41ff-80eb-b0b15efd1414/local-authority-districts-december-2017-generalised-clipped-boundaries-in-united-kingdom-wgs84

https://www.gov.uk/government/publications/covid-19-track-coronavirus-cases